package com.zyk.scaffold.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyk.scaffold.core.domain.PageFilter;
import com.zyk.scaffold.core.domain.PageResult;
import com.zyk.scaffold.common.enums.TenantUserTypeEnum;
import com.zyk.scaffold.common.enums.UserTypeEnum;
import com.zyk.scaffold.common.utils.AssertUtil;
import com.zyk.scaffold.common.utils.BeanCopyUtil;
import com.zyk.scaffold.common.utils.BusinessUtil;
import com.zyk.scaffold.common.utils.MD5Util;
import com.zyk.scaffold.user.controller.tenantuser.*;
import com.zyk.scaffold.user.controller.user.*;
import com.zyk.scaffold.user.entity.*;
import com.zyk.scaffold.user.mapper.TenantUserMapper;
import com.zyk.scaffold.user.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 租户-用户-部门关系 服务实现类
 * </p>
 *
 * @author zhouyk
 * @since 2022-11-04
 */
@Service
public class TenantUserServiceImpl extends ServiceImpl<TenantUserMapper, TenantUser> implements TenantUserService {

    @Autowired
    private TenantService tenantService;

    @Autowired
    private TenantUserService tenantUserService;

    @Autowired
    private TenantUserRoleService userRoleService;

    @Autowired
    private UserService userService;

    @Autowired
    private TenantRoleService tenantRoleService;


    @Override
    public List<Tenant> getTenantInfos(Long userId) {
        List<String> tenantCodes = this.list(Wrappers.lambdaQuery(TenantUser.class)
                .eq(TenantUser::getUserId, userId)
                .eq(TenantUser::getDeleted, Boolean.FALSE)
                .eq(TenantUser::getEnable, Boolean.TRUE)
        ).stream().map(TenantUser::getTenantCode).collect(Collectors.toList());
        return tenantService.getTenantInfos().stream().filter(item -> tenantCodes.contains(item.getCode())).collect(Collectors.toList());
    }

    @Override
    public TenantUser getTenantUserInfo(String tenantCode, Long userId) {
        TenantUser tenantUser = this.list(Wrappers.lambdaQuery(TenantUser.class)
                .eq(TenantUser::getUserId, userId)
                .eq(TenantUser::getTenantCode, tenantCode)
                .eq(TenantUser::getDeleted, Boolean.FALSE)
                .eq(TenantUser::getEnable, Boolean.TRUE))
                .stream()
                .findFirst()
                .orElse(null);
        return tenantUser;
    }

    @Override
    public Boolean addTenantUser(TenantUserNewRequ tenantUserNewRequ, Long userId, String tenantCode) {
        User user = userService.getUserByAccount(tenantUserNewRequ.getAccount());
        if(user == null) {
            UserNewRequ userNewRequ = BeanCopyUtil.copyProperties(tenantUserNewRequ, UserNewRequ::new);
            try {
                userNewRequ.setPassword(MD5Util.computeMD5("123456"));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                log.error("密码加密异常", e);
                AssertUtil.error("密码加密异常");
            }
            userNewRequ.setType(UserTypeEnum.USER_TYPE_BUSINESS.getCode());
            user = userService.addUser(userNewRequ, userId);
        }
        // 用户ID换租户用户ID
        TenantUser tenantUser = tenantUserService.loadTenantUserByUserId(user.getId(), tenantCode, null);
        AssertUtil.isNull(tenantUser, "邮箱账号已存在");
        tenantUser = new TenantUser();
        tenantUser.setUserId(user.getId());
        tenantUser.setTenantCode(tenantCode);
        tenantUser.setCreateUser(userId);
        tenantUser.setCreateTime(LocalDateTime.now());
        tenantUser.setLongTermEffective(1);
        tenantUser.setEnable(Boolean.TRUE);
        tenantUser.setType(TenantUserTypeEnum.TENANT_USER_TYPE_BUSINESS.getCode());
        tenantUserService.save(tenantUser);
        Long id = tenantUser.getId();
        List<Long> roleIds = tenantUserNewRequ.getRoleIds();
        if(id != null && CollectionUtils.isNotEmpty(roleIds)){
            List<Long> roleIdsNonNull = roleIds.stream().filter(Objects::nonNull).collect(Collectors.toList());
            List<TenantRole> rolesDb = tenantRoleService.getRolesByIds(roleIdsNonNull, tenantCode);
            List<Long> roleIdDbs = rolesDb.stream().map(TenantRole::getId).collect(Collectors.toList());
            List<TenantUserRole> lstTenantUserRole = roleIdDbs.stream().map(roleIdDb ->{
                TenantUserRole tenantUserRole = new TenantUserRole();
                tenantUserRole.setTenantUserId(id);
                tenantUserRole.setCreateUser(userId);
                tenantUserRole.setUpdateUser(userId);
                tenantUserRole.setTenantRoleId(roleIdDb);
                return tenantUserRole;
            }).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(lstTenantUserRole)){
                userRoleService.saveBatch(lstTenantUserRole);
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public PageResult<TenantUserInfosResp> pageFilterTenantUser(PageFilter<TenantUserPageFilterRequ> pageFilter, String tenantCode) {
        TenantUserPageFilterRequ filter = pageFilter.getFilter();
        if(null == filter){
            filter = new TenantUserPageFilterRequ();
        }else{
            if(CollectionUtils.isNotEmpty(filter.getRoleIds())){
                List<TenantUserRole> tenantUserRoles = userRoleService.getUserRoleByRoleIds(filter.getRoleIds());
                List<Long> userIds = tenantUserRoles.stream().map(TenantUserRole::getTenantUserId).collect(Collectors.toList());
                if(CollectionUtils.isEmpty(userIds)){
                    return PageResult.buildEmpty(pageFilter);
                }
                filter.setUserIds(userIds);
            }
        }
        filter.setType(TenantUserTypeEnum.TENANT_USER_TYPE_BUSINESS.getCode());
        filter.setTenantCode(tenantCode);
        Page<TenantUserInfosResp> page = this.baseMapper.selectUserPageFilter(pageFilter.toPage(), filter);
        PageResult<TenantUserInfosResp> pageResult = PageResult.build(page, TenantUserInfosResp::new);
        List<TenantUserInfosResp> records = pageResult.getRecords();

        if(CollectionUtils.isNotEmpty(records)){
            // 添加角色名称、创建人、修改人名称等
            List<Long> userId = records.stream().map(TenantUserInfosResp::getId).collect(Collectors.toList());
            List<TenantUserRole> userRolesByTenantUserIds = userRoleService.getUserRolesByUserIds(userId);
            List<Long> roleIds = userRolesByTenantUserIds.stream()
                    .map(TenantUserRole::getTenantRoleId).distinct().collect(Collectors.toList());
            Map<Long, String> mapRoleId2Name = tenantRoleService.getRolesByIds(roleIds, tenantCode).stream()
                    .collect(Collectors.toMap(TenantRole::getId, TenantRole::getName, (a, b) -> a));

            Map<Long, List<Long>> mapUserId2RoleIds = userRolesByTenantUserIds.stream()
                    .collect(Collectors.groupingBy(TenantUserRole::getTenantUserId, Collectors.mapping(TenantUserRole::getTenantRoleId, Collectors.toList())));
            Map<Long, List<String>> mapUserId2RoleNames = userRolesByTenantUserIds.stream()
                    .collect(Collectors.groupingBy(TenantUserRole::getTenantUserId, Collectors.mapping(userRole -> mapRoleId2Name.get(userRole.getTenantRoleId()), Collectors.toList())));

            ArrayList<Long> optionUserIds = new ArrayList<>();
            optionUserIds.addAll(records.stream().map(TenantUserInfosResp::getCreateUser).collect(Collectors.toList()));
            optionUserIds.addAll(records.stream().map(TenantUserInfosResp::getUpdateUser).collect(Collectors.toList()));
            Map<Long, String> mapUserId2Name = userService.listByIds(optionUserIds).stream()
                    .collect(Collectors.toMap(User::getId, User::getName, (a, b) -> a));

            for (TenantUserInfosResp record : records) {
                Long id = record.getId();
                List<Long> roleIdsTmp = mapUserId2RoleIds.get(id);
                if(null == roleIdsTmp){
                    roleIdsTmp = Collections.EMPTY_LIST;
                }
                record.setRoleIds(roleIdsTmp);
                List<String> roleNames = mapUserId2RoleNames.get(id);
                if(null == roleNames){
                    roleNames = Collections.EMPTY_LIST;
                }
                // 电话脱敏
                record.setPhone(BusinessUtil.mobileDesensitization(record.getPhone()));
                // 设置角色名称
                record.setRoleNames(roleNames);
                // 设置创建、修改用户名称
                record.setCreateUserName(mapUserId2Name.get(record.getCreateUser()));
                record.setUpdateUserName(mapUserId2Name.get(record.getUpdateUser()));
            }
        }
        return pageResult;
    }

    @Override
    public Boolean editedTenantUser(TenantUserEditedRequ tenantUserEditedRequ, Long userId, String tenantCode) {
        TenantUser tenantUserOld = this.getById(tenantUserEditedRequ.getId());
        if(tenantUserOld == null){
            AssertUtil.error("用户ID不存在");
        }
        if(TenantUserTypeEnum.TENANT_USER_TYPE_INNER.getCode().equals(tenantUserOld.getType())){
            AssertUtil.error("不能编辑内部用户");
        }
        TenantUser tenantUser = BeanCopyUtil.copyProperties(tenantUserEditedRequ, TenantUser::new);
        tenantUser.setUpdateUser(userId);
        boolean update = this.updateById(tenantUser);
        List<Long> roleIds = tenantUserEditedRequ.getRoleIds();
        if(CollectionUtils.isNotEmpty(roleIds)){
            List<Long> roleIdsNonNull = roleIds.stream().filter(Objects::nonNull).collect(Collectors.toList());
            List<TenantRole> rolesDb = tenantRoleService.getRolesByIds(roleIdsNonNull, tenantCode);
            List<Long> roleIdDbs = rolesDb.stream().map(TenantRole::getId).collect(Collectors.toList());
            List<TenantUserRole> lstTenantUserRole = roleIdDbs.stream().map(roleIdDb ->{
                TenantUserRole tenantUserRole = new TenantUserRole();
                tenantUserRole.setTenantUserId(tenantUserEditedRequ.getId());
                tenantUserRole.setCreateUser(userId);
                tenantUserRole.setUpdateUser(userId);
                tenantUserRole.setTenantRoleId(roleIdDb);
                return tenantUserRole;
            }).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(lstTenantUserRole)){
                userRoleService.UpdateBatch(lstTenantUserRole, tenantUserEditedRequ.getId(), userId);
            }
        }
        return update;
    }

    @Override
    public Boolean deletedTenantUser(TenantUserDeletedRequ tenantUserDeletedRequ, Long userId, String tenantCode) {
        Long id = tenantUserDeletedRequ.getId();
        UpdateWrapper<TenantUser> tenantUserUpdateWrapper = new UpdateWrapper<>();
        tenantUserUpdateWrapper
                .lambda()
                .eq(TenantUser::getId, id)
                .eq(TenantUser::getTenantCode, tenantCode)
                .set(TenantUser::getUpdateUser, userId)
                .set(TenantUser::getDeleted, Boolean.TRUE);
        boolean b = this.update(tenantUserUpdateWrapper);
        if(b){
            userRoleService.deletedUserRoleByUserId(id, userId);
        }
        return b;
    }

    @Override
    public Boolean disabledTenantUser(TenantUserDisableRequ tenantUserDisableRequ, Long userId, String tenantCode) {
        Long id = tenantUserDisableRequ.getId();
        UpdateWrapper<TenantUser> tenantUserUpdateWrapper = new UpdateWrapper<>();
        tenantUserUpdateWrapper
                .lambda()
                .eq(TenantUser::getId, id)
                .eq(TenantUser::getTenantCode, tenantCode)
                .set(TenantUser::getUpdateUser, userId)
                .set(TenantUser::getEnable, Boolean.FALSE);
        return this.update(tenantUserUpdateWrapper);
    }

    @Override
    public Boolean enabledTenantUser(TenantUserEnableRequ tenantUserEnableRequ, Long userId, String tenantCode) {
        Long id = tenantUserEnableRequ.getId();
        UpdateWrapper<TenantUser> tenantUserUpdateWrapper = new UpdateWrapper<>();
        tenantUserUpdateWrapper
                .lambda()
                .eq(TenantUser::getId, id)
                .eq(TenantUser::getTenantCode, tenantCode)
                .set(TenantUser::getUpdateUser, userId)
                .set(TenantUser::getEnable, Boolean.TRUE);
        return this.update(tenantUserUpdateWrapper);
    }

    @Override
    public TenantUser loadTenantUserByUserId(Long userId, String tenantCode, Boolean enable) {
        if(userId == null){
            return null;
        }
        QueryWrapper<TenantUser> tenantUserQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<TenantUser> lambda = tenantUserQueryWrapper.lambda();
        lambda.eq(TenantUser::getTenantCode, tenantCode);
        lambda.eq(TenantUser::getUserId, userId);
        lambda.eq(enable != null, TenantUser::getEnable, enable);
        lambda.eq(TenantUser::getDeleted, Boolean.FALSE);
        TenantUser one = this.getOne(tenantUserQueryWrapper, false);
        if(one == null){
            return null;
        }
        return one;
    }

    @Override
    public List<TenantInfoResp> tenantList(Long userId) {
        List<User> users = userService.listByIds(Arrays.asList(userId));
        if(CollectionUtils.isEmpty(users)){
            return Collections.emptyList();
        }
        User user = users.get(0);
        List<Tenant> tenantInfos = tenantService.getTenantInfos();
        if(UserTypeEnum.USER_TYPE_INNER.getCode().equals(user.getType())){
            return BeanCopyUtil.copyListProperties(tenantInfos, TenantInfoResp::new);
        }
        List<String> tenantCodes = this.lambdaQuery()
                .eq(TenantUser::getUserId, userId)
                .eq(TenantUser::getDeleted, Boolean.FALSE)
                .eq(TenantUser::getEnable, Boolean.TRUE)
                .list()
                .stream()
                .map(TenantUser::getTenantCode)
                .distinct()
                .collect(Collectors.toList());
        return tenantInfos.stream()
                .filter(item -> tenantCodes.contains(item.getCode()))
                .map(item -> BeanCopyUtil.copyProperties(item, TenantInfoResp::new))
                .collect(Collectors.toList());
    }
}
